package com.ficus.road.maintain.service.smartnew.primaryScreening;

import com.alibaba.fastjson.JSONArray;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ficus.road.maintain.core.model.*;
import com.ficus.road.maintain.core.model.smartnew.PrimaryGpsRoadMapDTO;
import com.ficus.road.maintain.core.model.smartnew.PrimaryRoadSectionDTO;
import com.ficus.road.maintain.dao.HitDao;
import com.ficus.road.maintain.dao.smartnew.primaryScreening.PrimaryGpsRoadMapDao;
import com.ficus.road.maintain.dao.smartnew.primaryScreening.PrimaryRoadSectionDao;
import com.ficus.road.maintain.util.LngLonUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.opencsv.CSVReader;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.data.geo.Point;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import java.io.FileReader;
import java.io.IOException;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@Service
@Slf4j
@RequiredArgsConstructor
public class PrimaryRoadSectionService {

    private final PrimaryRoadSectionDao primaryRoadSectionDao;
    private final PrimaryGpsRoadMapDao primaryGpsRoadMapDao;
    private final HitDao hitDao;
    //    MILD = 0; //轻
//    MODERATE = 1; // 中
//    SEVERE = 2; //重

    private HashSet<String> realSet = Sets.newHashSet("航城路_0.0_1.756", "沪南公路_50.102_52.885", "华东北路_0.0_1.466",
            "川南奉公路_32.696_34.914", "唐陆路_1.286_2.371", "唐陆路_2.371_3.299", "金海路_1.058_2.654", "川南奉公路_40.681_43.113",
            "沪南公路_52.885_55.147", "金海路_0.765_1.058", "金海路_2.654_3.192", "航三路_3.722_5.219", "航津路_0.0_0.725",
            "老芦公路_2.002_5.272", "川南奉公路_34.914_36.486", "沪南公路_55.147_57.586", "金海路_3.192_4.559", "周祝公路_8.806_10.254",
            "三鲁公路_0.898_1.761", "航三路_7.242_9.054", "唐陆路_3.299_4.649", "南滨公路_0.0_2.5", "华东路_3486.078_3487.035",
            "东葛路_0.0_1.34", "申东路_0.0_1.13", "行南路_0.0_1.1", "行南路_1.1_1.384", "绕城高速_3.231_6.077",
            "绕城高速_2.139_3.231", "环南大道_46.734_48.708", "环南大道_45.04_46.734", "环南大道_48.708_49.252", "南祝路_5.444_7.762",
            "顾唐路_4.385_5.617", "施湾路_0.765_1.611", "汇庆路_0.812_1.411", "宣黄公路_3.398_4.79", "康新公路_0.0_1.346",
            "川南奉公路_36.486_40.681", "航三路_5.219_6.135", "航三路_2.037_3.722", "六奉公路_11.949_14.182", "六奉公路_10.782_11.949",
            "康新公路_2.652_4.024", "南团公路_4.563_6.535", "航浦路_0.0_0.742", "航浦路_0.742_1.708", "凌空北路_8.741_10.141",
            "两港公路_8.525_10.598", "凌空北路_7.868_8.741", "南滨公路_2.5_5.456", "航三路_0.783_2.037", "航三路_0.0_0.783",
            "六奉公路_9.26_10.782", "六奉公路_7.313_9.26", "三鲁公路_0.0_0.898", "周祝公路_7.894_8.806", "凌空北路_6.939_7.868",
            "川沙路_12.586_13.309", "大川公路_5.593_6.807", "下盐路_0.0_2.245", "凯庆路_0.0_1.067", "下盐路_2.245_4.433",
            "康新公路_1.79_2.652", "汇庆路_0.0_0.812", "川沙路_13.309_14.884", "顾唐路_5.617_7.175", "航城路_1.756_2.4",
            "航三路_6.135_7.242", "金海路_0.0_0.765", "施湾路_0.0_0.765");

    //沥青路面
    private final Map<String, Map<String, Float>> weightMapAsphalt = new HashMap<>() {{
        // 裂缝
        put("PIC_CRACK_RESULT_PIC_CRACK", new HashMap<>() {{
            put("MILD", 0.6F * 1.5F);
            put("MODERATE", 1.0F * 1.5F);
            put("SEVERE", 1.0F * 1.5F);
        }});

        //坑塘
        put("PIC_POTHOLES_RESULT_DEPRESSION", new HashMap<>() {{
            put("MILD", 0.6F);
            put("MODERATE", 1.0F);
            put("SEVERE", 1.0F);
        }});
        //龟裂,这里认为跟裂缝一样
        put("PIC_CRACK_RESULT_CRACKED", new HashMap<>() {{
            put("MILD", 0.6F * 1.5F);
            put("MODERATE", 1.0F * 1.5F);
            put("SEVERE", 1.0F * 1.5F);
        }});
        //沉陷
        put("PIC_POTHOLES_RESULT_SETTLEMENT", new HashMap<>() {{
            put("MILD", 0.6F);
            put("MODERATE", 0.8F);
            put("SEVERE", 1.0F);
        }});
        //车辙
        put("PIC_CRACK_RESULT_CAR_RUT", new HashMap<>() {{
            put("MILD", 0.6F);
            put("MODERATE", 0.8F);
            put("SEVERE", 1.0F);
        }});

    }};

    //水泥路面
    private final Map<String, Map<String, Float>> weightMapCement = new HashMap<>() {{
        // 裂缝
        put("PIC_CRACK_RESULT_PIC_CRACK", new HashMap<>() {{
            put("MILD", 0.6F * 7F);
            put("MODERATE", 0.8F * 7F);
            put("SEVERE", 1.0F * 7F);
        }});

        //板块碎裂
        put("PIC_CRACK_RESULT_BROKEN_BOARD", new HashMap<>() {{
            put("MILD", 0.6F * 7F);
            put("MODERATE", 0.8F * 7F);
            put("SEVERE", 1.0F * 7F);
        }});
    }};

    public PrimaryGpsRoadMapDTO geoSearch(GpsLocation gpsLocation) {
        org.springframework.data.geo.Point point = new Point(gpsLocation.getLongitude(), gpsLocation.getLatitude());
        List<AggregationOperation> aggregationList = new ArrayList<>();
        aggregationList.add(new GeoNearDocument(new Query(), point, "distance", DISTANCE_GPS_THRESHOLD * 10));
        Aggregation agg = Aggregation.newAggregation(aggregationList);
        List<PrimaryGpsRoadMapDTO> result = primaryGpsRoadMapDao.aggregate(agg);
        // distance排序,返回最近的
        Optional<PrimaryGpsRoadMapDTO> first = result.stream().min(Comparator.comparing(PrimaryGpsRoadMapDTO::getDistance));
        return first.orElse(null);
    }
    public PrimaryGpsRoadMapDTO geoSearchforName(String roadName, GpsLocation gpsLocation) {
        List<PrimaryGpsRoadMapDTO> result = primaryGpsRoadMapDao.findByQuery(new Query(Criteria.where("road_name").is(roadName).and("sequence").is(1)));
        // distance排序,返回最近的
//        Optional<PrimaryGpsRoadMapDTO> first = result.stream().min(Comparator.comparing(PrimaryGpsRoadMapDTO::getDistance));
//        return first.orElse(null);
//        return result.get(0);
//    }
        double minDistance = Double.MAX_VALUE;
        PrimaryGpsRoadMapDTO nearestRoad = null;

        for (PrimaryGpsRoadMapDTO road : result) {
            GpsLocation gpsLocation1 = new GpsLocation();
            gpsLocation1.setLongitude(road.getLocation().get(0));
            gpsLocation1.setLatitude(road.getLocation().get(1));
            double distanceToRoad = calculateDistance(gpsLocation,gpsLocation1);
            if (distanceToRoad < minDistance) {
                minDistance = distanceToRoad;
                nearestRoad = road;
            }
        }

        return nearestRoad;
    }
    public static double calculateDistance(GpsLocation gps1, GpsLocation gps2) {
        final int R = 6371; // 地球半径（单位：公里）

        double latDistance = Math.toRadians(gps2.getLatitude() - gps1.getLatitude());
        double lonDistance = Math.toRadians(gps2.getLongitude() - gps1.getLongitude());

        double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2)
                + Math.cos(Math.toRadians(gps1.getLatitude())) * Math.cos(Math.toRadians(gps2.getLatitude()))
                * Math.sin(lonDistance / 2) * Math.sin(lonDistance / 2);

        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

        double distance = R * c; // 结果单位: 公里

        return distance;
    }

    private static final int DISTANCE_GPS_THRESHOLD = 5;

    private final Map<String, String> typeMap = new HashMap<>() {{
        put("PIC_CRACK_RESULT_BROKEN_BOARD", "板块碎裂");
        put("PIC_CRACK_RESULT_PIC_CRACK", "裂缝");
        put("PIC_CRACK_RESULT_CAR_RUT", "车辙");
        put("PIC_POTHOLES_RESULT_SETTLEMENT", "沉陷");
        put("PIC_CRACK_RESULT_CRACKED", "龟裂");
        put("PIC_POTHOLES_RESULT_DEPRESSION", "坑塘");
    }};
//    @PostConstruct
    public void calculate() {
        Map<String, PrimaryRoadSectionDTO> roadMap = primaryRoadSectionDao.findAll().stream().
                peek(road -> {
                    if (road.getArea() == null) {
                        road.setArea(0D);
                    }
                    road.setDamagedArea(0);
                    road.setHitIds(null);
                    road.setTypeCount(null);
                }).collect(Collectors.toMap(PrimaryRoadSectionDTO::getId, v -> v));
        List<Hit> byQuery = hitDao.findByQuery(new Query(Criteria.where("attrs.confirmation.status")
                .in(Lists.newArrayList(Confirmation.ConfirmationStatus.CORRECT, Confirmation.ConfirmationStatus.INCORRECT))
                .and("type").in(Lists.newArrayList("PIC_CRACK_RESULT_BROKEN_BOARD", "PIC_CRACK_RESULT_PIC_CRACK",
                        "PIC_CRACK_RESULT_CAR_RUT", "PIC_POTHOLES_RESULT_SETTLEMENT", "PIC_CRACK_RESULT_CRACKED", "PIC_POTHOLES_RESULT_DEPRESSION"))));
        AtomicInteger miss = new AtomicInteger();
        AtomicInteger used = new AtomicInteger();
        byQuery.forEach(hit -> {
            GpsLocation gpsLocation = hit.getAttrs().getGpsLocation();
            PrimaryGpsRoadMapDTO gpsRoadMapDTO = geoSearch(gpsLocation);
            if (Objects.isNull(gpsRoadMapDTO)) {
                if (roadMap.keySet().stream().anyMatch(t -> t.contains(hit.getAttrs().getRoadName()))) {
                    miss.getAndIncrement();
                    log.info("匹配不到,hitId={},roadName={},gps={},miss={}", hit.getId(),
                            hit.getAttrs().getRoadName(), gpsLocation, miss.get());
                }
                return;
            }

            PrimaryRoadSectionDTO roadSectionDTO = roadMap.get(gpsRoadMapDTO.getRoadId());
            if (Objects.isNull(roadSectionDTO)) {
                return;
            }
            String roadType = roadSectionDTO.getRoadType();
            if (StringUtils.isEmpty(roadType)) {
                return;
            }
            hitDao.update(hit.getId(), Update.update("road_id", roadSectionDTO.getId()));

            float weight;
            String type = hit.getType();
            if (Objects.isNull(hit.getSeverityType())) {
                hit.setSeverityType(SeverityType.MILD);
            }
            String road = roadSectionDTO.getId();
            float scale = 1;
            String hitRoad = "";
            if (realSet.contains(road)) {
                scale = scale * 0.6f;
                hitRoad = "是";
            } else {
                if (hit.getAttrs().getConfirmation().getStatus().equals(Confirmation.ConfirmationStatus.INCORRECT)) {
                    return;
                }
            }

            if (roadType.equals("沥青路面")) {
                if (!weightMapAsphalt.containsKey(type)) {
                    return;
                }
                Map<String, Float> stringFloatMap = weightMapAsphalt.get(type);
                weight = stringFloatMap.getOrDefault(hit.getSeverityType().toString(), 0f);
            } else {
                if (!weightMapCement.containsKey(type)) {
                    return;
                }
                Map<String, Float> stringFloatMap = weightMapCement.get(type);
                weight = stringFloatMap.getOrDefault(hit.getSeverityType().toString(), 0f);
            }
            roadSectionDTO.setDamagedArea(roadSectionDTO.getDamagedArea() + weight * scale);
            List<String> hitIds = roadSectionDTO.getHitIds() == null ? new ArrayList<>() : roadSectionDTO.getHitIds();
            hitIds.add(hit.getId());
            used.getAndIncrement();
            roadSectionDTO.setHitIds(hitIds);
            Map<String, Integer> typeCount = roadSectionDTO.getTypeCount();
            if (typeCount == null) {
                typeCount = Maps.newHashMap();
            }
            if (!typeCount.containsKey(typeMap.get(type))) {
                typeCount.put(typeMap.get(type), 0);
            }
            typeCount.put(typeMap.get(type), typeCount.get(typeMap.get(type)) + 1);
            roadSectionDTO.setTypeCount(typeCount);
            roadSectionDTO.setHitRoad(hitRoad);
        });
        log.info("miss count={}, used count={}, total count={}", miss.get(), used.getAndIncrement(), byQuery.size());
        roadMap.values().forEach(road -> {
            float score;
            float dr;
            if (road.getDamagedArea() == 0) {
                score = 100;
            } else {
                dr = (float) (100 * road.getDamagedArea() / road.getArea());
                if (StringUtils.pathEquals("沥青路面", road.getRoadType())) {
                    score = (float) (100 - 15 * Math.pow(dr, 0.412));
                } else {
                    score = (float) (100 - 10.66 * Math.pow(dr, 0.461));
                }
            }

            primaryRoadSectionDao.update(road.getId(), Update.update("damaged_area", road.getDamagedArea())
                    .set("hit_ids", road.getHitIds())
                    .set("score", score)
                    .set("hit_count", road.getHitIds() == null ? 0 : road.getHitIds().size())
                    .set("hit_road", road.getHitRoad())
                    .set("type_count", road.getTypeCount()));
        });
        System.out.println(1);
    }

//    @PostConstruct
    public void calculate1() {
        log.info("========================== begin to calculate===============================");
        Map<String, PrimaryRoadSectionDTO> roadMap = primaryRoadSectionDao.findAll().stream().
                peek(road -> {
                    if (road.getArea() == null) {
                        road.setArea(0D);
                    }
                    road.setDamagedArea(0);
                    road.setHitIds(null);
                    road.setTypeCount(null);
                }).collect(Collectors.toMap(PrimaryRoadSectionDTO::getId, v -> v));
        List<Hit> byQuery = hitDao.findByQuery(new Query(Criteria.where("attrs.confirmation.status")
                .in(Lists.newArrayList(Confirmation.ConfirmationStatus.CORRECT))
                .and("type").in(Lists.newArrayList("PIC_CRACK_RESULT_BROKEN_BOARD", "PIC_CRACK_RESULT_PIC_CRACK",
                        "PIC_CRACK_RESULT_CAR_RUT", "PIC_POTHOLES_RESULT_SETTLEMENT", "PIC_CRACK_RESULT_CRACKED", "PIC_POTHOLES_RESULT_DEPRESSION"))));
        AtomicInteger miss = new AtomicInteger();
        AtomicInteger used = new AtomicInteger();
        byQuery.forEach(hit -> {
            GpsLocation gpsLocation = hit.getAttrs().getGpsLocation();
            PrimaryGpsRoadMapDTO gpsRoadMapDTO = geoSearch(gpsLocation);
            if (Objects.isNull(gpsRoadMapDTO)) {
                if (roadMap.keySet().stream().anyMatch(t -> t.contains(hit.getAttrs().getRoadName()))) {
                    miss.getAndIncrement();
                    log.info("匹配不到,hitId={},roadName={},gps={},miss={}", hit.getId(),
                            hit.getAttrs().getRoadName(), gpsLocation, miss.get());
                }
                return;
            }

            PrimaryRoadSectionDTO roadSectionDTO = roadMap.get(gpsRoadMapDTO.getRoadId());
            if (Objects.isNull(roadSectionDTO)) {
                return;
            }
            String roadType = roadSectionDTO.getRoadType();
            if (StringUtils.isEmpty(roadType)) {
                return;
            }

            float weight;
            String type = hit.getType();
            if (Objects.isNull(hit.getSeverityType())) {
                hit.setSeverityType(SeverityType.MILD);
            }
            String road = roadSectionDTO.getId();
            float scale = 1;
            String hitRoad = "";
            if (realSet.contains(road)) {
                scale = scale * 3;
                hitRoad = "是";
            }

            if (roadType.equals("沥青路面")) {
                if (!weightMapAsphalt.containsKey(type)) {
                    return;
                }
                Map<String, Float> stringFloatMap = weightMapAsphalt.get(type);
                weight = stringFloatMap.getOrDefault(hit.getSeverityType().toString(), 0f);
            } else {
                if (!weightMapCement.containsKey(type)) {
                    return;
                }
                Map<String, Float> stringFloatMap = weightMapCement.get(type);
                weight = stringFloatMap.getOrDefault(hit.getSeverityType().toString(), 0f);
            }
            roadSectionDTO.setDamagedArea(roadSectionDTO.getDamagedArea() + weight * scale);
            List<String> hitIds = roadSectionDTO.getHitIds() == null ? new ArrayList<>() : roadSectionDTO.getHitIds();
            hitIds.add(hit.getId());
            used.getAndIncrement();
            roadSectionDTO.setHitIds(hitIds);
            Map<String, Integer> typeCount = roadSectionDTO.getTypeCount();
            if (typeCount == null) {
                typeCount = Maps.newHashMap();
            }
            if (!typeCount.containsKey(typeMap.get(type))) {
                typeCount.put(typeMap.get(type), 0);
            }
            typeCount.put(typeMap.get(type), typeCount.get(typeMap.get(type)) + 1);
            roadSectionDTO.setTypeCount(typeCount);
            roadSectionDTO.setHitRoad(hitRoad);
        });
        log.info("miss count={}, used count={}, total count={}", miss.get(), used.getAndIncrement(), byQuery.size());
        roadMap.values().forEach(road -> {
            float score;
            float dr;
            if (road.getDamagedArea() == 0) {
                score = 100;
            } else {
                dr = (float) (100 * road.getDamagedArea() / road.getArea());
                if (StringUtils.pathEquals("沥青路面", road.getRoadType())) {
                    score = (float) (100 - 15 * Math.pow(dr, 0.412));
                } else {
                    score = (float) (100 - 10.66 * Math.pow(dr, 0.461));
                }
            }

            primaryRoadSectionDao.update(road.getId(), Update.update("damaged_area", road.getDamagedArea())
                    .set("hit_ids", road.getHitIds())
                    .set("score", score)
                    .set("hit_count", road.getHitIds() == null ? 0 : road.getHitIds().size())
                    .set("hit_road", road.getHitRoad())
                    .set("type_count", road.getTypeCount()));
        });
        System.out.println(1);
    }

    //按照上下行计算
    public Map<String, PrimaryRoadSectionDTO>  calculate2(String roadDirection) {
        log.info("========================== begin to calculate===============================");
        Map<String, PrimaryRoadSectionDTO> roadMap = primaryRoadSectionDao.findAll().stream().
                peek(road -> {
                    if (road.getArea() == null) {
                        road.setArea(0D);
                    }
                    road.setDamagedArea(0);
                    road.setHitIds(null);
                    road.setTypeCount(null);
                }).collect(Collectors.toMap(PrimaryRoadSectionDTO::getId, v -> v));
        log.info("RoadSize:"+roadMap.size());
        List<Hit> byQuery = hitDao.findByQuery(new Query(Criteria.where("attrs.confirmation.status")
                .in(Lists.newArrayList(Confirmation.ConfirmationStatus.CORRECT))
                .and("type").in(Lists.newArrayList("PIC_CRACK_RESULT_BROKEN_BOARD", "PIC_CRACK_RESULT_PIC_CRACK",
                        "PIC_CRACK_RESULT_CAR_RUT", "PIC_POTHOLES_RESULT_SETTLEMENT", "PIC_CRACK_RESULT_CRACKED", "PIC_POTHOLES_RESULT_DEPRESSION"))));
        AtomicInteger miss = new AtomicInteger();
        AtomicInteger used = new AtomicInteger();
        byQuery.forEach(hit -> {
            if(hit.getAttrs().getRoadDirection()==null || !hit.getAttrs().getRoadDirection().equals(roadDirection))
            {
                log.info("道路方向"+hit.getAttrs().getRoadDirection()+",跳出本次循环！");
                return;
            }
            GpsLocation gpsLocation = hit.getAttrs().getGpsLocation();
            PrimaryGpsRoadMapDTO gpsRoadMapDTO = geoSearch(gpsLocation);
            if (Objects.isNull(gpsRoadMapDTO)) {
                if (roadMap.keySet().stream().anyMatch(t -> t.contains(hit.getAttrs().getRoadName()))) {
                    miss.getAndIncrement();
                    log.info("匹配不到,hitId={},roadName={},gps={},miss={}", hit.getId(),
                            hit.getAttrs().getRoadName(), gpsLocation, miss.get());
                }
                return;
            }

            PrimaryRoadSectionDTO roadSectionDTO = roadMap.get(gpsRoadMapDTO.getRoadId());
            if (Objects.isNull(roadSectionDTO)) {
                return;
            }
            String roadType = roadSectionDTO.getRoadType();
            if (StringUtils.isEmpty(roadType)) {
                return;
            }

            float weight;
            String type = hit.getType();
            if (Objects.isNull(hit.getSeverityType())) {
                hit.setSeverityType(SeverityType.MILD);
            }
            String road = roadSectionDTO.getId();
            float scale = 1;
            String hitRoad = "";
            if (realSet.contains(road)) {
                scale = scale * 3;
                hitRoad = "是";
            }

            if (roadType.equals("沥青路面")) {
                if (!weightMapAsphalt.containsKey(type)) {
                    return;
                }
                Map<String, Float> stringFloatMap = weightMapAsphalt.get(type);
                weight = stringFloatMap.getOrDefault(hit.getSeverityType().toString(), 0f);
            } else {
                if (!weightMapCement.containsKey(type)) {
                    return;
                }
                Map<String, Float> stringFloatMap = weightMapCement.get(type);
                weight = stringFloatMap.getOrDefault(hit.getSeverityType().toString(), 0f);
            }
            roadSectionDTO.setDamagedArea(roadSectionDTO.getDamagedArea() + weight * scale);
            List<String> hitIds = roadSectionDTO.getHitIds() == null ? new ArrayList<>() : roadSectionDTO.getHitIds();
            hitIds.add(hit.getId());
            used.getAndIncrement();
            roadSectionDTO.setHitIds(hitIds);
            Map<String, Integer> typeCount = roadSectionDTO.getTypeCount();
            if (typeCount == null) {
                typeCount = Maps.newHashMap();
            }
            if (!typeCount.containsKey(typeMap.get(type))) {
                typeCount.put(typeMap.get(type), 0);
            }
            typeCount.put(typeMap.get(type), typeCount.get(typeMap.get(type)) + 1);
            roadSectionDTO.setTypeCount(typeCount);
            roadSectionDTO.setHitRoad(hitRoad);
        });
        log.info("miss count={}, used count={}, total count={}", miss.get(), used.getAndIncrement(), byQuery.size());
        roadMap.values().forEach(road -> {
            road.setArea(road.getArea()/2);
            float score;
            float dr;
            if (road.getDamagedArea() == 0) {
                score = 100;
            } else {
                dr = (float) (100 * road.getDamagedArea() / road.getArea());
                if (StringUtils.pathEquals("沥青路面", road.getRoadType())) {
                    score = (float) (100 - 15 * Math.pow(dr, 0.412));
                } else {
                    score = (float) (100 - 10.66 * Math.pow(dr, 0.461));
                }
            }
            road.setScore(score);
        });
        System.out.println(1);
        return roadMap;

    }
//    public void

    //    @PostConstruct
    public void initRoadSectionData() {
        String fileName = "/home/ficus/Downloads/20230514大中修智慧决策-路格数据.csv";
        CSVReader reader;
        try {
            reader = new CSVReader(new FileReader(fileName));
            String[] line;
            reader.readNext();
            List<PrimaryRoadSectionDTO> lists = Lists.newArrayList();
            Set<String> ids = Sets.newHashSet();
            while ((line = reader.readNext()) != null) {
                PrimaryRoadSectionDTO roadSectionDTO = new PrimaryRoadSectionDTO();
                roadSectionDTO.setRoadId(line[0]);
                roadSectionDTO.setRoadCode(line[1]);
                roadSectionDTO.setRoadName(line[2]);
                roadSectionDTO.setStartStake(StringUtils.isEmpty(line[3]) ? null : Double.parseDouble(line[3]));
                roadSectionDTO.setEndStake(StringUtils.isEmpty(line[4]) ? null : Double.parseDouble(line[4]));
                roadSectionDTO.setWidth(StringUtils.isEmpty(line[5]) ? null : Double.parseDouble(line[5]));
                roadSectionDTO.setLength(StringUtils.isEmpty(line[6]) ? null : Double.parseDouble(line[6]));
                roadSectionDTO.setArea(StringUtils.isEmpty(line[7]) ? null : Double.parseDouble(line[7]));

                roadSectionDTO.generalRoadId();
                if (ids.contains(roadSectionDTO.getId())) {
                    continue;
                } else {
                    ids.add(roadSectionDTO.getId());
                }

                String gaodeGps = line[9];
                if (!StringUtils.isEmpty(gaodeGps)) {
                    List<Coordinate> coordinates = JSONArray.parseArray(gaodeGps, Coordinate.class);
                    coordinates.forEach(coordinate -> {
                        double[] wgs84 = LngLonUtil.gcj02towgs84(Double.parseDouble(coordinate.getX()), Double.parseDouble(coordinate.getY()));
                        coordinate.setX(String.valueOf(wgs84[0]));
                        coordinate.setY(String.valueOf(wgs84[1]));
                    });
                    roadSectionDTO.setCoordinates(coordinates);
                }
                roadSectionDTO.setLevel(line[10]);
                roadSectionDTO.setRoadType(line[11]);
                roadSectionDTO.setSource(line[12]);
                roadSectionDTO.setLastOverhaulYear(StringUtils.isEmpty(line[13]) ? null : Double.parseDouble(line[13]));

                lists.add(roadSectionDTO);
            }
            primaryRoadSectionDao.deleteAll();
            primaryRoadSectionDao.insert(lists);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


    public void createGpsRoadMap() {
        primaryGpsRoadMapDao.deleteAll();
        // stream()用时17m
        long startCreate = System.currentTimeMillis();
        primaryRoadSectionDao.findAll().stream()
                .filter(t -> CollectionUtils.isNotEmpty(t.getCoordinates()))
                .forEach(roadInfo -> {
                    AtomicInteger index = new AtomicInteger(0);
                    List<Coordinate> coordinates = roadInfo.getCoordinates();
                    System.out.println("采样前数据量: " + coordinates.size());
                    coordinates = LngLonUtil.gpsSampling(coordinates, DISTANCE_GPS_THRESHOLD);
                    System.out.println("采样后数据量: " + coordinates.size());
                    coordinates.forEach(coordinate -> {
                        PrimaryGpsRoadMapDTO gpsRoadMapDTO = PrimaryGpsRoadMapDTO.builder()
                                .roadName(roadInfo.getRoadName())
                                .location(Arrays.asList(Double.parseDouble(coordinate.getX()), Double.parseDouble(coordinate.getY())))
                                .roadId(roadInfo.getId())
                                .roadCode(roadInfo.getRoadCode())
                                .sequence(index.getAndIncrement())
                                .build();
                        primaryGpsRoadMapDao.saveOrUpdate(gpsRoadMapDTO);
                    });
                });
        log.info("创建理论覆盖点集耗时: {}s", (System.currentTimeMillis() - startCreate) / 1000);
    }

    public long countAll() {
        Query query = new Query();
        query.fields().include("id");
        return primaryRoadSectionDao.count(query);
    }


    public void calculateTest(String road_name) {
        Map<String, PrimaryRoadSectionDTO> roadMap = primaryRoadSectionDao.findByQuery(new Query(Criteria.where("road_name")
                        .in(Lists.newArrayList(road_name))
                )).stream().
                peek(road -> {
                    if (road.getArea() == null) {
                        road.setArea(0D);
                    }
                    road.setDamagedArea(0);
                    road.setHitIds(null);
                    road.setTypeCount(null);
                }).collect(Collectors.toMap(PrimaryRoadSectionDTO::getId, v -> v));
        long aYearAgoTimestamp = System.currentTimeMillis() / 1000 - 31536000;
        int year = LocalDate.now().getYear();
        if (year%4 == 0){
            aYearAgoTimestamp -= 86400;
        }
        List<Hit> byQuery = hitDao.findByQuery(new Query(Criteria.where("attrs.road_name")
                .in(Lists.newArrayList(road_name))
                .and("attrs.status").nin(HitStatusEnum.NEW)
                .and("first_hit_time").gte(aYearAgoTimestamp)
                .and("type").in(Lists.newArrayList("PIC_CRACK_RESULT_BROKEN_BOARD", "PIC_CRACK_RESULT_PIC_CRACK",
                        "PIC_CRACK_RESULT_CAR_RUT", "PIC_POTHOLES_RESULT_SETTLEMENT", "PIC_CRACK_RESULT_CRACKED", "PIC_POTHOLES_RESULT_DEPRESSION"))));
        AtomicInteger miss = new AtomicInteger();
        AtomicInteger used = new AtomicInteger();
        byQuery.forEach(hit -> {
            GpsLocation gpsLocation = hit.getAttrs().getGpsLocation();
            PrimaryGpsRoadMapDTO gpsRoadMapDTO = geoSearch(gpsLocation);
            if (Objects.isNull(gpsRoadMapDTO)) {
                gpsRoadMapDTO = geoSearchforName(hit.getAttrs().getRoadName(),gpsLocation);
            }
            if (Objects.isNull(gpsRoadMapDTO)) {
                if (roadMap.keySet().stream().anyMatch(t -> t.contains(hit.getAttrs().getRoadName()))) {
                    miss.getAndIncrement();
                    log.info("匹配不到,hitId={},roadName={},gps={},miss={}", hit.getId(),
                            hit.getAttrs().getRoadName(), gpsLocation, miss.get());
                }
                return;
            }else {
                Update update = new Update().set("sectionRoadId",gpsRoadMapDTO.getRoadId());
                hitDao.update(hit.getId(),update);
            }

            PrimaryRoadSectionDTO roadSectionDTO = roadMap.get(gpsRoadMapDTO.getRoadId());
            if (Objects.isNull(roadSectionDTO)) {
                return;
            }
            String roadType = roadSectionDTO.getRoadType();
            if (StringUtils.isEmpty(roadType)) {
                return;
            }
            hitDao.update(hit.getId(), Update.update("road_id", roadSectionDTO.getId()));

            float weight;
            String type = hit.getType();
            if (Objects.isNull(hit.getSeverityType())) {
                hit.setSeverityType(SeverityType.MILD);
            }
            String road = roadSectionDTO.getId();
            float scale = 1;
            String hitRoad = "";
            if (realSet.contains(road)) {
                scale = scale * 0.6f;
                hitRoad = "是";
            } else {
                if (hit.getAttrs().getConfirmation().getStatus().equals(Confirmation.ConfirmationStatus.INCORRECT)) {
                    return;
                }
            }

            if (roadType.equals("沥青路面")) {
                if (!weightMapAsphalt.containsKey(type)) {
                    return;
                }
                Map<String, Float> stringFloatMap = weightMapAsphalt.get(type);
                weight = stringFloatMap.getOrDefault(hit.getSeverityType().toString(), 0f);
            } else {
                if (!weightMapCement.containsKey(type)) {
                    return;
                }
                Map<String, Float> stringFloatMap = weightMapCement.get(type);
                weight = stringFloatMap.getOrDefault(hit.getSeverityType().toString(), 0f);
            }
            roadSectionDTO.setDamagedArea(roadSectionDTO.getDamagedArea() + weight * scale);
            List<String> hitIds = roadSectionDTO.getHitIds() == null ? new ArrayList<>() : roadSectionDTO.getHitIds();
            hitIds.add(hit.getId());
            used.getAndIncrement();
            roadSectionDTO.setHitIds(hitIds);
            Map<String, Integer> typeCount = roadSectionDTO.getTypeCount();
            if (typeCount == null) {
                typeCount = Maps.newHashMap();
            }
            if (!typeCount.containsKey(typeMap.get(type))) {
                typeCount.put(typeMap.get(type), 0);
            }
            typeCount.put(typeMap.get(type), typeCount.get(typeMap.get(type)) + 1);
            roadSectionDTO.setTypeCount(typeCount);
            roadSectionDTO.setHitRoad(hitRoad);
        });
        log.info("miss count={}, used count={}, total count={}", miss.get(), used.getAndIncrement(), byQuery.size());
        roadMap.values().forEach(road -> {
            float score;
            float dr;
            if (road.getDamagedArea() == 0) {
                score = 100;
            } else {
                dr = (float) (100 * road.getDamagedArea() / road.getArea());
                if (StringUtils.pathEquals("沥青路面", road.getRoadType())) {
                    score = (float) (100 - 15 * Math.pow(dr, 0.412));
                } else {
                    score = (float) (100 - 10.66 * Math.pow(dr, 0.461));
                }
            }

            primaryRoadSectionDao.update(road.getId(), Update.update("damaged_area", road.getDamagedArea())
                    .set("hit_ids", road.getHitIds())
                    .set("score", score)
                    .set("hit_count", road.getHitIds() == null ? 0 : road.getHitIds().size())
                    .set("hit_road", road.getHitRoad())
                    .set("type_count", road.getTypeCount()));
        });
        System.out.println(1);
    }

    /**
     * 道路初筛手动接口
     */
    public void calculateTest() {
        Map<String, PrimaryRoadSectionDTO> roadMap = primaryRoadSectionDao.findAll().stream().
                peek(road -> {
                    if (road.getArea() == null) {
                        road.setArea(0D);
                    }
                    road.setDamagedArea(0);
                    road.setHitIds(null);
                    road.setTypeCount(null);
                }).collect(Collectors.toMap(PrimaryRoadSectionDTO::getId, v -> v));
        long aYearAgoTimestamp = System.currentTimeMillis() / 1000 - 31536000;
        int year = LocalDate.now().getYear();
        if (year%4 == 0){
            aYearAgoTimestamp -= 86400;
        }
        List<Hit> byQuery = hitDao.findByQuery(new Query(Criteria.where("attrs.road_name")
                .in(Lists.newArrayList("川南奉公路","东靖路","东葛路","川沙路","川周公路","周祝公路","草高公路","草高支路","川六公路","东奉线","金高路","金海路","环东大道",
                        "杨高路","迎宾大道","拱极东路","顾曹路","顾高路", "南六公路", "锦绣东路", "张东路", "顾唐路", "张江路", "航津路", "海滨路", "航城路", "南团公路", "锦绣路", "华夏路",
                        "华洲路", "济阳路", "沪南公路", "高科东路", "集海路", "汇庆路", "江东路", "南港公路", "康新公路", "六奉公路", "金桥路", "龙东大道", "航三路", "罗山路", "中高公路",
                        "龚路公路", "内环地面路", "老泥公路", "内环辅一路", "凌白公路", "浦东北路", "绕城高速", "周邓公路", "凌空北路", "上川路", "张杨北路", "赵高公路", "南祝路", "凌空路",
                        "秀浦西路", "盐大公路", "大川公路", "宣黄公路", "东新线", "秀浦路", "高科西路", "华东路", "港城路", "港华路", "华夏东路", "五洲大道", "华东北路", "下盐路", "施湾路",
                        "双江路", "六陈路", "航浦路", "古恩路", "航南公路", "沪南路", "港建路", "大同路", "东塘公路", "东陆路", "内环辅二路", "护塘路", "机场大道", "江东支路", "两港公路",
                        "老芦公路", "秀沿路", "丹东线", "南滨支路", "南滨公路", "唐陆路", "新奉公路", "盐朝公路", "东电路", "金科路", "南芦公路", "云顺路", "S3", "军港公路", "沈梅路",
                        "三三公路", "唐陆公路", "洲海路", "奚阳公路", "陈行公路", "远航路", "欧高公路", "闻居路", "油管路", "崇景路", "罗山南路", "明港路", "北艾路", "林恒路", "大芦西路",
                        "年家浜东路", "浦星公路", "海高路", "巨峰路", "越海路", "环南大道", "施新路", "川北公路", "高科中路", "川滨路", "上南路", "康梧路", "行南路", "航塘公路", "沈杜公路",
                        "申江南路", "军民公路", "港绣路", "杨高北一路", "年家浜路", "江月东路", "三鲁公路", "景明路", "申东路", "凌海路", "凯庆路", "孙桥路", "林礼路"))
                .and("attrs.status").nin(HitStatusEnum.NEW)
                .and("first_hit_time").gte(aYearAgoTimestamp)
                .and("type").in(Lists.newArrayList("PIC_CRACK_RESULT_BROKEN_BOARD", "PIC_CRACK_RESULT_PIC_CRACK",
                        "PIC_CRACK_RESULT_CAR_RUT", "PIC_POTHOLES_RESULT_SETTLEMENT", "PIC_CRACK_RESULT_CRACKED", "PIC_POTHOLES_RESULT_DEPRESSION"))));
        AtomicInteger miss = new AtomicInteger();
        AtomicInteger used = new AtomicInteger();
        byQuery.forEach(hit -> {
            GpsLocation gpsLocation = hit.getAttrs().getGpsLocation();
            PrimaryGpsRoadMapDTO gpsRoadMapDTO = geoSearch(gpsLocation);
            if (Objects.isNull(gpsRoadMapDTO)) {
                gpsRoadMapDTO = geoSearchforName(hit.getAttrs().getRoadName(),gpsLocation);
            }
            if (Objects.isNull(gpsRoadMapDTO)) {
                if (roadMap.keySet().stream().anyMatch(t -> t.contains(hit.getAttrs().getRoadName()))) {
                    miss.getAndIncrement();
                    gpsRoadMapDTO = geoSearchforName(hit.getAttrs().getRoadName(),gpsLocation);
                    log.info("匹配不到,hitId={},roadName={},gps={},miss={}", hit.getId(),
                            hit.getAttrs().getRoadName(), gpsLocation, miss.get());
                }
                return;
            }else {
                Update update = new Update().set("sectionRoadId",gpsRoadMapDTO.getRoadId());
                hitDao.update(hit.getId(),update);
            }

            PrimaryRoadSectionDTO roadSectionDTO = roadMap.get(gpsRoadMapDTO.getRoadId());
            if (Objects.isNull(roadSectionDTO)) {
                return;
            }
            String roadType = roadSectionDTO.getRoadType();
            if (StringUtils.isEmpty(roadType)) {
                return;
            }
            hitDao.update(hit.getId(), Update.update("road_id", roadSectionDTO.getId()));

            float weight;
            String type = hit.getType();
            if (Objects.isNull(hit.getSeverityType())) {
                hit.setSeverityType(SeverityType.MILD);
            }
            String road = roadSectionDTO.getId();
            float scale = 1;
            String hitRoad = "";
            if (realSet.contains(road)) {
                scale = scale * 0.6f;
                hitRoad = "是";
            } else {
                if (hit.getAttrs().getConfirmation().getStatus().equals(Confirmation.ConfirmationStatus.INCORRECT)) {
                    return;
                }
            }

            if (roadType.equals("沥青路面")) {
                if (!weightMapAsphalt.containsKey(type)) {
                    return;
                }
                Map<String, Float> stringFloatMap = weightMapAsphalt.get(type);
                weight = stringFloatMap.getOrDefault(hit.getSeverityType().toString(), 0f);
            } else {
                if (!weightMapCement.containsKey(type)) {
                    return;
                }
                Map<String, Float> stringFloatMap = weightMapCement.get(type);
                weight = stringFloatMap.getOrDefault(hit.getSeverityType().toString(), 0f);
            }
            roadSectionDTO.setDamagedArea(roadSectionDTO.getDamagedArea() + weight * scale);
            List<String> hitIds = roadSectionDTO.getHitIds() == null ? new ArrayList<>() : roadSectionDTO.getHitIds();
            hitIds.add(hit.getId());
            used.getAndIncrement();
            roadSectionDTO.setHitIds(hitIds);
            Map<String, Integer> typeCount = roadSectionDTO.getTypeCount();
            if (typeCount == null) {
                typeCount = Maps.newHashMap();
            }
            if (!typeCount.containsKey(typeMap.get(type))) {
                typeCount.put(typeMap.get(type), 0);
            }
            typeCount.put(typeMap.get(type), typeCount.get(typeMap.get(type)) + 1);
            roadSectionDTO.setTypeCount(typeCount);
            roadSectionDTO.setHitRoad(hitRoad);
        });
        log.info("miss count={}, used count={}, total count={}", miss.get(), used.getAndIncrement(), byQuery.size());
        roadMap.values().forEach(road -> {
            float score;
            float dr;
            if (road.getDamagedArea() == 0) {
                score = 100;
            } else {
                dr = (float) (100 * road.getDamagedArea() / road.getArea());
                if (StringUtils.pathEquals("沥青路面", road.getRoadType())) {
                    score = (float) (100 - 15 * Math.pow(dr, 0.412));
                } else {
                    score = (float) (100 - 10.66 * Math.pow(dr, 0.461));
                }
            }

            primaryRoadSectionDao.update(road.getId(), Update.update("damaged_area", road.getDamagedArea())
                    .set("hit_ids", road.getHitIds())
                    .set("score", score)
                    .set("hit_count", road.getHitIds() == null ? 0 : road.getHitIds().size())
                    .set("hit_road", road.getHitRoad())
                    .set("type_count", road.getTypeCount()));
        });
        System.out.println(1);
    }

    public void DeleteCalculate() {
        List<Hit> byQuery = hitDao.findByQuery(new Query(Criteria.where("attrs.road_name")
                .in(Lists.newArrayList(""))
                .and("attrs.status").nin(HitStatusEnum.NEW)
                .and("type").in(Lists.newArrayList("PIC_CRACK_RESULT_BROKEN_BOARD", "PIC_CRACK_RESULT_PIC_CRACK",
                        "PIC_CRACK_RESULT_CAR_RUT", "PIC_POTHOLES_RESULT_SETTLEMENT", "PIC_CRACK_RESULT_CRACKED", "PIC_POTHOLES_RESULT_DEPRESSION"))));
        byQuery.forEach(hit -> {
            hitDao.deleteById(hit.getId());
        });

    }

}
